package de.fhkl.thatsstroke;

import java.io.File;
import java.util.UUID;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.Toast;
import android.widget.VideoView;
import de.fhkl.thatsstroke.StrokeService.StrokeBinder;

/**
 * Custom video player activity to display and rate the incoming videos.
 */
public class VideoPlayer extends Activity
{
	/**
	 * The file extension to use to play the video file. Must match the file
	 * extension used in WhatsStroke.
	 */
	private static final String FILE_EXTENSION = ".mp4";

	// GUI references
	private VideoView mVideoView;
	private ImageButton mStrokeButton;
	private ImageButton mNoButton;

	/** ID of the video to play */
	private UUID mVideoId;

	/** Path to the video to play */
	private String mVideoPath;

	/** BroadcastReceiver for broadcast intents from the service */
	private BroadcastReceiver mReceiver;

	/**
	 * ServiceConnection to retrieve a reference for a save way to call methods
	 * from the service
	 */
	private ServiceConnection mConnection;

	/** Reference to the underlying service */
	private StrokeService mService;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		// Must be called before creating content!

		// as long as this window is visible to the user, keep the device's
		// screen turned on and bright.
		this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		// hide title bar
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);

		// displays this activity in fullscreen mode.
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

		// Now start creating content.

		mVideoId = (UUID) getIntent().getExtras().get("de.fhkl.thatsstroke.VideoId");

		mVideoPath = getMediaFile();

		setContentView(R.layout.activity_video_player);

		// Build view
		mStrokeButton = (ImageButton) findViewById(R.id.strokeButton);
		mStrokeButton.setOnClickListener(new StrokeButtonListener());

		mNoButton = (ImageButton) findViewById(R.id.no_strokeButton);
		mNoButton.setOnClickListener(new NoButtonListener());

		mVideoView = (VideoView) findViewById(R.id.videoView);
		mVideoView.setVideoPath(mVideoPath);
		mVideoView.setOnPreparedListener(new OnPreparedListener()
		{
			@Override
			public void onPrepared(MediaPlayer mp)
			{
				try
				{
					mVideoView.start();
				}
				catch (Exception e)
				{
					Toast.makeText(VideoPlayer.this, R.string.video_broken, Toast.LENGTH_LONG).show();
					Log.w("VideoPlayer", "Videofile broken");
				}
				mp.start();
			}
		});

		// In most cases this won't do anything. Service should be already
		// running. Let's try to start it just in case it doesn't.
		Intent intent = new Intent(getApplicationContext(), StrokeService.class);
		getApplicationContext().startService(intent);

		mConnection = new StrokeServiceConnection();
		mReceiver = new StrokeBroadcastReceiver();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		return false;
	}

	@Override
	protected void onStart()
	{
		super.onStart();

		this.bindService(new Intent(this, StrokeService.class), mConnection, 0);
		this.registerReceiver(mReceiver, new IntentFilter(Broadcast.ACCEPT_RATING_ID));
	}

	@Override
	protected void onStop()
	{
		this.unregisterReceiver(mReceiver);
		this.unbindService(mConnection);

		super.onStop();
	}

	/**
	 * Returns the full path of the mediaFile corresponding to the UUID in the
	 * intent this activity was started with.
	 * 
	 * @return path as s
	 */
	private String getMediaFile()
	{
		File mediaFileDir;

		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
		{
			UUID id = (UUID) getIntent().getExtras().get("de.fhkl.thatsstroke.VideoId");

			mediaFileDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
					getText(R.string.app_name) + File.separator + id + FILE_EXTENSION);

			if (mediaFileDir.exists())
			{
				return mediaFileDir.getAbsolutePath();
			}
			else
			{
				Log.w("VideoPlayer", "MediaFile does not exist");
			}
		}
		else
		{
			Log.w("VideoPlayer", "No SD Card found");
		}
		return null;
	}

	/**
	 * Event that is called when the StrokeButton is pressed
	 */
	private class StrokeButtonListener implements OnClickListener
	{
		@Override
		public void onClick(View v)
		{
			mVideoView.stopPlayback();

			AsyncTask<Void, Void, Void> at = new AsyncTask<Void, Void, Void>()
			{
				@Override
				protected Void doInBackground(Void... params)
				{
					mService.sendRating(mVideoId, true);
					return null;
				}
			};

			at.execute();

			// Successful completion of this activity, not the rating!
			setResult(RESULT_OK);
			finish();
		}
	}

	/**
	 * Event that is called when the NoButton is pressed
	 */
	private class NoButtonListener implements OnClickListener
	{
		@Override
		public void onClick(View v)
		{
			mVideoView.stopPlayback();

			AsyncTask<Void, Void, Void> at = new AsyncTask<Void, Void, Void>()
			{
				@Override
				protected Void doInBackground(Void... params)
				{
					mService.sendRating(mVideoId, false);
					return null;
				}
			};

			at.execute();

			// Successful completion of this activity, not the rating!
			setResult(RESULT_OK);
			finish();
		}
	}

	/**
	 * Safe connection to the underlying service over a returned weak reference.
	 * Like many callbacks from the system, the methods on this class are called
	 * from the main thread of your process.
	 */
	public class StrokeServiceConnection implements ServiceConnection
	{
		@Override
		public void onServiceConnected(ComponentName name, IBinder binder)
		{
			mService = ((StrokeBinder) binder).getService();

			Log.i("StrokeServiceConnection", "Service " + mService);
		}

		@Override
		public void onServiceDisconnected(ComponentName name)
		{
		}
	}

	/**
	 * Broadcast receiver to receive and react to broadcast messages from the
	 * underlying service.
	 */
	public class StrokeBroadcastReceiver extends BroadcastReceiver
	{
		@Override
		public void onReceive(Context context, Intent intent)
		{
			String action = intent.getAction();

			if (action.equals(Broadcast.ACCEPT_RATING_ID))
			{
				mVideoView.stopPlayback();
				VideoPlayer.this.setResult(RESULT_CANCELED);
				VideoPlayer.this.finish();
			}
		}
	}
}
